<?php
/**
 * Created by PHPStorm
 * User: xiest
 * Date: 2021/4/6
 * Email: <939369942@qq.com>
 */
namespace basic\services\upload\storage;

use basic\base\BaseUpload;
use basic\exceptions\UploadException;
use OSS\Core\OssException;
use OSS\OssClient;
use think\exception\ValidateException;

class Oss extends BaseUpload
{
    /**
     *
     * @var mixed|null
     */
    protected $accessKey;
    /**
     *
     * @var mixed|null
     */
    protected $secretKey;

    /**
     * 空间域名 Domain
     * @var mixed
     */
    protected $uploadUrl;
    /**
     * 存储空间名称  公开空间
     * @var mixed
     */
    protected $storageName;
    /**
     * COS使用  所属地域
     * @var mixed|null
     */
    protected $storageRegion;

    /**
     * 句柄
     * @var \OSS\OssClient
     */
    protected $handle;


    protected function init(array $config)
    {
        parent::init($config);
        $this->accessKey = $config['accessKey'] ?? null;
        $this->secretKey = $config['secretKey'] ?? null;
        $this->uploadUrl = $config['uploadUrl'] ?? null;
        $this->storageName = $config['storageName'] ?? null;
        $this->storageRegion = $config['storageRegion'] ?? null;
    }


    /**
     * @return mixed|void
     * User: xiest
     * Date: 2021/4/6
     * @throws \OSS\Core\OssException
     */
    public function app()
    {
        if (!$this->accessKey || !$this->secretKey) {
            throw new UploadException('Please configure accessKey and secretKey');
        }

        $this->handle = new OssClient($this->accessKey, $this->secretKey, $this->storageRegion);
        if(!$this->handle->doesBucketExist($this->storageName)){
            $this->handle->createBucket($this->storageName);
        }

        return $this->handle;
    }

    /**
     * 上传文件
     * @param string $file
     * @return array|bool|mixed|\StdClass
     * @throws \OSS\Core\OssException
     * User: xiest
     * Date: 2021/4/6
     */
    public function move(string $file = 'file')
    {
        $fileHandle = app()->request->file($file);
        if(!$fileHandle) return $this->setError('Upload file does not exist!');

        if($this->validate) {
            try{
                $errorMsg = [
                    $file . '.filesize' => 'Upload filesize error',
                    $file . '.fileExt' => 'Upload fileExt error',
                    $file . '.fileMime' => 'Upload fileMine error'
                ];
                validate([$file=>$this->validate],$errorMsg)->check([$file=>$fileHandle]);
            }catch (ValidateException $e){
                return $this->setError($e->getMessage());
            }
        }

        $key = $this->getName($fileHandle->getOriginalExtension());

        try {
            $uploadInfo = $this->app()->uploadFile($this->storageName,$key,$fileHandle->getRealPath());


            if(!$uploadInfo['info']['url'])
                return $this->setError('Upload failure');

            $this->fileInfo->uploadInfo = $uploadInfo;

            $this->fileInfo->realName = $fileHandle->getOriginalMime();

            $this->fileInfo->filePath = $this->uploadUrl.'/'.$key;


            $this->fileInfo->fileName = $key;

            return  $this->fileInfo;
        }catch (UploadException $e) {
            return $this->setError($e->getMessage());
        }

    }


    /**
     * 删除文件
     * @param string $key
     * @return mixed|string|null
     * User: xiest
     * Date: 2021/4/6
     */
    public function remove(string $key)
    {
        try {
            return $this->app()->deleteObject($this->storageName, $key);
        } catch (OssException $e) {
            return $this->setError($e->getMessage());
        }
    }

    public function getKeys($callbackUrl = '', $dir = '')
    {
        $base64CallbackBody = base64_encode(json_encode([
            'callbackUrl' => $callbackUrl,
            'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
            'callbackBodyType' => "application/x-www-form-urlencoded"
        ]));

        $policy = json_encode([
            'expiration' => $this->gmtIso8601(time() + 30),
            'conditions' =>
                [
                    [0 => 'content-length-range', 1 => 0, 2 => 1048576000],
                    [0 => 'starts-with', 1 => '$key', 2 => $dir]
                ]
        ]);
        $base64Policy = base64_encode($policy);
        $signature = base64_encode(hash_hmac('sha1', $base64Policy, $this->secretKey, true));
        return [
            'accessid' => $this->accessKey,
            'host' => $this->uploadUrl,
            'policy' => $base64Policy,
            'signature' => $signature,
            'expire' => time() + 30,
            'callback' => $base64CallbackBody,
            'type' => 'OSS'
        ];
    }

    protected function gmtIso8601($time)
    {
        $dtStr = date("c", $time);
        $mydatetime = new \DateTime($dtStr);
        $expiration = $mydatetime->format(\DateTime::ISO8601);
        $pos = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);
        return $expiration . "Z";
    }


    /**
     * 文件流上传
     * @param $content
     * @param $key
     * @return mixed|string
     * @throws \OSS\Core\OssException
     * User: xiest
     * Date: 2021/4/6
     */
    public function stream($content, $key)
    {
        try {
            if (!$key) {
                $key = $this->getName();
            }

            $uploadInfo = $this->app()->putObject($this->storageName,$key,$content);
            if(!$uploadInfo['info']['url'])
            {
                return $this->setError('Upload failure');
            }

            $this->fileInfo->uploadInfo = $uploadInfo;
            $this->fileInfo->realName = $key;
            $this->fileInfo->filePath = $this->uploadUrl.'/'.$key;
            $this->fileInfo->fileName = $key;
            return $this->fileInfo;
        }catch (UploadException $e){
            return $this->setError('Upload failure');
        }
    }
}